/*
 *  Copyright 2005 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.service.questionnaire.impl;

import com.blandware.atleap.common.util.PartialCollection;
import com.blandware.atleap.common.util.QueryInfo;
import com.blandware.atleap.model.questionnaire.AnswerOption;
import com.blandware.atleap.model.questionnaire.FilledQuestionnaire;
import com.blandware.atleap.model.questionnaire.Question;
import com.blandware.atleap.model.questionnaire.Questionnaire;
import com.blandware.atleap.persistence.core.PageDAO;
import com.blandware.atleap.persistence.exception.DeleteException;
import com.blandware.atleap.persistence.questionnaire.AnswerOptionDAO;
import com.blandware.atleap.persistence.questionnaire.FilledQuestionnaireDAO;
import com.blandware.atleap.persistence.questionnaire.QuestionDAO;
import com.blandware.atleap.persistence.questionnaire.QuestionnaireDAO;
import com.blandware.atleap.service.core.impl.BaseManagerImpl;
import com.blandware.atleap.service.exception.BeanAlreadyExistsException;
import com.blandware.atleap.service.exception.BeanNotFoundException;
import com.blandware.atleap.service.exception.OwnerNotFoundException;
import com.blandware.atleap.service.questionnaire.QuestionnaireManager;

import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * <p>Implementation of QuestionnaireManager</p>
 * <p><a href="QuestionnaireManagerImpl.java.html"><i>View source</i></a></p>
 *
 * @author Roman Puchkovskiy <a href="mailto:roman.puchkovskiy@blandware.com">
 *         &lt;roman.puchkovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.4 $ $Date: 2008/01/13 17:19:59 $
 */
public class QuestionnaireManagerImpl extends BaseManagerImpl
        implements QuestionnaireManager {

    /**
     * Questionnaire DAO
     */
	protected QuestionnaireDAO questionnaireDAO;

    /**
     * Question DAO
     */
    protected QuestionDAO questionDAO;

    /**
     * Answer option DAO
     */
    protected AnswerOptionDAO answerOptionDAO;

    /**
     * Filled questionnaire DAO
     */
    protected FilledQuestionnaireDAO filledQuestionnaireDAO;

    /**
     * Page DAO
     */
	protected PageDAO pageDAO;

	/**
	 * Creates new instance of QuestionnaireManagerImpl.
	 */
	public QuestionnaireManagerImpl() {
	}

    /**
     * Sets DAO for operating with questionnaires.
     *
     * @param questionnaireDAO the DAO to set
     */
	public void setQuestionnaireDAO(QuestionnaireDAO questionnaireDAO) {
		this.questionnaireDAO = questionnaireDAO;
	}

    /**
     * Sets DAO to work with questions.
     *
     * @param questionDAO DAO to set
     */
    public void setQuestionDAO(QuestionDAO questionDAO) {
        this.questionDAO = questionDAO;
    }

    /**
     * Sets DAO to work with answer options.
     *
     * @param answerOptionDAO DAO to set
     */
    public void setAnswerOptionDAO(AnswerOptionDAO answerOptionDAO) {
        this.answerOptionDAO = answerOptionDAO;
    }

    /**
     * Sets DAO to work with filled questionnaires.
     *
     * @param filledQuestionnaireDAO DAO to set
     */
    public void setFilledQuestionnaireDAO(
            FilledQuestionnaireDAO filledQuestionnaireDAO) {
        this.filledQuestionnaireDAO = filledQuestionnaireDAO;
    }

    /**
     * Sets DAO for operating with pages.
     *
     * @param pageDAO the DAO to set
     */
	public void setPageDAO(PageDAO pageDAO) {
		this.pageDAO = pageDAO;
	}

    // Q U E S T I O N N A I R E S

	//~ CRUD Methods ================================================================

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#createQuestionnaire(com.blandware.atleap.model.questionnaire.Questionnaire, java.util.Map)
	 */
	public Long createQuestionnaire(Questionnaire questionnaire, Map linkedObjects) throws BeanAlreadyExistsException {

		if ( log.isDebugEnabled() ) {
			log.debug("Creating new questionnaire...");
		}

		if ( pageDAO.hasDuplicates(questionnaire) ) {
			// linkable item already exists
			String errorMessage = "Linkable item with URI '" + questionnaire.getUri() + "' already exists";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new BeanAlreadyExistsException(errorMessage);
		}

		// linkable item does not exist
		Long questionnaireId = questionnaireDAO.createQuestionnaire(questionnaire, linkedObjects);
		if ( log.isDebugEnabled() ) {
			log.debug("New questionnaire has been created successfully. Its ID is " + questionnaireId);
		}
		return questionnaireId;
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#retrieveQuestionnaire(Long)
	 */
	public Questionnaire retrieveQuestionnaire(Long questionnaireId) {
		Questionnaire questionnaire;
		questionnaire = questionnaireDAO.retrieveQuestionnaire(questionnaireId);

		return questionnaire;
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#updateQuestionnaire(com.blandware.atleap.model.questionnaire.Questionnaire, java.util.Map)
	 */
	public void updateQuestionnaire(Questionnaire questionnaire, Map linkedObjects) throws BeanAlreadyExistsException {

        // remove questionnaire from cache in order to prevent Hibernate from assigning new version number
		questionnaireDAO.removeFromCache(questionnaire);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating questionnaire...");
		}

		if ( pageDAO.hasDuplicates(questionnaire) ) {
			// linkable item already exists
			String errorMessage = "Linkable item with URI '" + questionnaire.getUri() + "' already exists";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new BeanAlreadyExistsException(errorMessage);
		}

		// linkable item does not exist
		questionnaireDAO.updateQuestionnaire(questionnaire, linkedObjects);

		if ( log.isDebugEnabled() ) {
			log.debug("Questionnaire was updated successfully.");
		}
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#updateQuestionnaire(com.blandware.atleap.model.questionnaire.Questionnaire)
	 */
	public void updateQuestionnaire(Questionnaire questionnaire) throws BeanAlreadyExistsException {
		updateQuestionnaire(questionnaire, null);
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#deleteQuestionnaire(Long)
	 */
	public void deleteQuestionnaire(Long questionnaireId) throws DeleteException, BeanNotFoundException {
		Questionnaire questionnaire = questionnaireDAO.retrieveQuestionnaire(questionnaireId);
		if ( questionnaire == null ) {
			String errorMessage = "Questionnaire with ID=" + questionnaireId + " does not exist";
			throw new BeanNotFoundException(errorMessage);
		}
		questionnaireDAO.deleteQuestionnaire(questionnaire);
		if ( log.isDebugEnabled() ) {
			log.debug("Deleted questionnaire: ID=" + questionnaireId);
		}
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#listQuestionnaires(com.blandware.atleap.common.util.QueryInfo)
	 */
	public PartialCollection listQuestionnaires(QueryInfo queryInfo) {
		return questionnaireDAO.listQuestionnaires(queryInfo);
	}

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#copyQuestionnaire(com.blandware.atleap.model.questionnaire.Questionnaire, java.util.Map)
     */
    public Questionnaire copyQuestionnaire(Questionnaire questionnaire,
                                           Map suffixMap) {
        Questionnaire copy = questionnaireDAO.copyQuestionnaire(questionnaire,
                                                                suffixMap);

        List questions = new ArrayList(questionnaire.getQuestions());
        for (Iterator i = questions.iterator(); i.hasNext(); ) {
            Question question = (Question) i.next();
            Question questionCopy = questionDAO.copyQuestion(question, copy);

            List answerOptions = new ArrayList(question.getAnswerOptions());
            for (Iterator j = answerOptions.iterator(); j.hasNext(); ) {
                AnswerOption answerOption = (AnswerOption) j.next();
                answerOptionDAO.copyAnswerOption(answerOption, questionCopy);
            }
        }

        return copy;
    }

    //  Q U E S T I O N S

	//~ CRUD Methods ================================================================

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#createQuestion(com.blandware.atleap.model.questionnaire.Question, Long)
	 */
	public Long createQuestion(Question question, Long questionnaireId)
            throws BeanNotFoundException, BeanAlreadyExistsException {

		if ( log.isDebugEnabled() ) {
			log.debug("Creating new question...");
		}

		Questionnaire questionnaire;
		questionnaire = questionnaireDAO.retrieveQuestionnaire(questionnaireId);

		if ( questionnaire == null ) {
			String errorMessage = "No questionnaire with ID=" + questionnaireId + "could be found";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new OwnerNotFoundException(errorMessage);
		}

/*
		if ( pageDAO.hasDuplicates(contentField, questionnaireId) ) {
			throw new BeanAlreadyExistsException("Content field with the same identifier already exists on owner with ID=" + questionnaireId);
		}
*/

		Long questionId = questionDAO.createQuestion(question, questionnaire);

		if ( log.isDebugEnabled() ) {
			log.debug("Question has been created successfully. Its ID is " + questionId);
		}
		return questionId;
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#retrieveQuestion(Long)
	 */
	public Question retrieveQuestion(Long questionId) {
		Question question;
		question = questionDAO.retrieveQuestion(questionId);
		return question;
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#updateQuestion(com.blandware.atleap.model.questionnaire.Question, Long)
	 */
	public void updateQuestion(Question question, Long questionnaireId)
            throws BeanNotFoundException, BeanAlreadyExistsException {

		// remove question from cache in order to prevent Hibernate from
        // assigning new version number
		questionDAO.removeFromCache(question);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating question with ID=" + question.getId() + "...");
		}

		Questionnaire questionnaire;
		questionnaire = questionnaireDAO.retrieveQuestionnaire(questionnaireId);

		if ( questionnaire == null ) {
			String errorMessage = "No questionnaire with ID=" + questionnaireId + "could be found";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new OwnerNotFoundException(errorMessage);
		}

/*
		if ( questionDAO.hasDuplicates(question, questionnaireId) ) {
			throw new BeanAlreadyExistsException("Content field with the same identifier already exists on owner with ID=" + questionnaireId);
		}
*/

		questionDAO.updateQuestion(question, questionnaire);

		if ( log.isDebugEnabled() ) {
			log.debug("Question was updated successfully.");
		}
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#deleteQuestion(Long)
	 */
	public void deleteQuestion(Long questionId)
            throws BeanNotFoundException {
		if ( log.isDebugEnabled() ) {
			log.debug("Deleting question with ID=" + questionId);
		}

		Question question = questionDAO.retrieveQuestion(questionId);
		if ( question == null ) {
			String errorMessage = "No question with ID=" + questionId + "could be found";
			throw new BeanNotFoundException(errorMessage);
		}

		questionDAO.deleteQuestion(question);

		if ( log.isDebugEnabled() ) {
			log.debug("Question has been deleted successfully");
		}
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#listQuestions(com.blandware.atleap.common.util.QueryInfo)
	 */
	public PartialCollection listQuestions(QueryInfo queryInfo) {
		return questionDAO.listQuestions(queryInfo);
	}

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#moveQuestion(com.blandware.atleap.model.questionnaire.Question, boolean)
     */
    public void moveQuestion(Question question, boolean up) {
        questionDAO.moveQuestion(question, up);
    }

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#getQuestionFirstLastOccupiedPositions(Long)
     */
    public Integer[] getQuestionFirstLastOccupiedPositions(Long ownerId) {
        return questionDAO.getFirstLastOccupiedPositions(ownerId);
    }

    // ~ Finders ================================================================

	//  A N S W E R   O P T I O N S

	//~ CRUD Methods ================================================================

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#createAnswerOption(com.blandware.atleap.model.questionnaire.AnswerOption, Long)
	 */
	public Long createAnswerOption(AnswerOption answerOption, Long questionId)
            throws BeanNotFoundException, BeanAlreadyExistsException {

		if ( log.isDebugEnabled() ) {
			log.debug("Creating new answer option...");
		}

		Question question;
		question = questionDAO.retrieveQuestion(questionId);

		if ( question == null ) {
			String errorMessage = "No question with ID=" + questionId + "could be found";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new OwnerNotFoundException(errorMessage);
		}

/*
		if ( pageDAO.hasDuplicates(contentField, questionId) ) {
			throw new BeanAlreadyExistsException("Content field with the same identifier already exists on owner with ID=" + questionId);
		}
*/

		Long answerOptionId = answerOptionDAO.createAnswerOption(answerOption, question);

		if ( log.isDebugEnabled() ) {
			log.debug("Answer option has been created successfully. Its ID is " + answerOptionId);
		}
		return answerOptionId;
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#retrieveAnswerOption(Long)
	 */
	public AnswerOption retrieveAnswerOption(Long answerOptionId) {
		AnswerOption answerOption;
		answerOption = answerOptionDAO.retrieveAnswerOption(answerOptionId);
		return answerOption;
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#updateAnswerOption(com.blandware.atleap.model.questionnaire.AnswerOption, Long)
	 */
	public void updateAnswerOption(AnswerOption answerOption, Long questionId)
            throws BeanNotFoundException, BeanAlreadyExistsException {

		// remove answer option from cache in order to prevent Hibernate from
        // assigning new version number
		answerOptionDAO.removeFromCache(answerOption);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating answer option with ID=" + answerOption.getId() + "...");
		}

		Question question;
		question = questionDAO.retrieveQuestion(questionId);

		if ( question == null ) {
			String errorMessage = "No question with ID=" + questionId + "could be found";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new OwnerNotFoundException(errorMessage);
		}

/*
		if ( questionDAO.hasDuplicates(answerOption, questionId) ) {
			throw new BeanAlreadyExistsException("Content field with the same identifier already exists on owner with ID=" + questionId);
		}
*/

		answerOptionDAO.updateAnswerOption(answerOption, question);

		if ( log.isDebugEnabled() ) {
			log.debug("Answer option was updated successfully.");
		}
	}

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#deleteAnswerOption(Long)
	 */
	public void deleteAnswerOption(Long answerOptionId)
            throws BeanNotFoundException {
		if ( log.isDebugEnabled() ) {
			log.debug("Deleting answer option with ID=" + answerOptionId);
		}

		AnswerOption answerOption = answerOptionDAO.retrieveAnswerOption(answerOptionId);
		if ( answerOption == null ) {
			String errorMessage = "No answer option with ID=" + answerOptionId + "could be found";
			throw new BeanNotFoundException(errorMessage);
		}

		answerOptionDAO.deleteAnswerOption(answerOption);

		if ( log.isDebugEnabled() ) {
			log.debug("Answer option has been deleted successfully");
		}
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#listAnswerOptions(com.blandware.atleap.common.util.QueryInfo)
	 */
	public PartialCollection listAnswerOptions(QueryInfo queryInfo) {
		return answerOptionDAO.listAnswerOptions(queryInfo);
	}

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#moveAnswerOption(com.blandware.atleap.model.questionnaire.AnswerOption, boolean)
     */
    public void moveAnswerOption(AnswerOption answerOption, boolean up) {
        answerOptionDAO.moveAnswerOption(answerOption, up);
    }

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#getAnswerOptionFirstLastOccupiedPositions(Long)
     */
    public Integer[] getAnswerOptionFirstLastOccupiedPositions(Long ownerId) {
        return answerOptionDAO.getFirstLastOccupiedPositions(ownerId);
    }

    //  F I L L E D   Q U E S T I O N N A I R E S

    //~ CRUD Methods ================================================================

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#createFilledQuestionnaire(com.blandware.atleap.model.questionnaire.FilledQuestionnaire, Long)
     */
    public Long createFilledQuestionnaire(FilledQuestionnaire filledQuestionnaire,
                                          Long questionnaireId)
            throws OwnerNotFoundException {
		if ( log.isDebugEnabled() ) {
			log.debug("Creating new filled questionnaire...");
		}

        Questionnaire questionnaire = questionnaireDAO.retrieveQuestionnaire(questionnaireId);
        if (questionnaire == null) {
            String errorMessage = "Can't find a questionnaire with ID="
                    + questionnaireId;
            throw new OwnerNotFoundException(errorMessage);
        }

		Long filledQuestionnaireId = filledQuestionnaireDAO.createFilledQuestionnaire(filledQuestionnaire, questionnaire);
		if ( log.isDebugEnabled() ) {
			log.debug("New filled questionnaire has been created successfully. Its ID is " + filledQuestionnaireId);
		}
		return filledQuestionnaireId;
    }

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#retrieveFilledQuestionnaire(Long)
     */
    public FilledQuestionnaire retrieveFilledQuestionnaire(Long filledQuestionnaireId) {
        FilledQuestionnaire filledQuestionnaire;
        filledQuestionnaire = filledQuestionnaireDAO.retrieveFilledQuestionnaire(filledQuestionnaireId);
        return filledQuestionnaire;
    }

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#deleteFilledQuestionnaire(Long)
     */
    public void deleteFilledQuestionnaire(Long filledQuestionnaireId)
            throws BeanNotFoundException {
		FilledQuestionnaire filledQuestionnaire = filledQuestionnaireDAO.retrieveFilledQuestionnaire(filledQuestionnaireId);
		if ( filledQuestionnaire == null ) {
			String errorMessage = "Filled questionnaire with ID=" + filledQuestionnaireId + " does not exist";
			throw new BeanNotFoundException(errorMessage);
		}
		filledQuestionnaireDAO.deleteFilledQuestionnaire(filledQuestionnaire);
		if ( log.isDebugEnabled() ) {
			log.debug("Deleted filled questionnaire: ID=" + filledQuestionnaireId);
		}
    }

    // ~ Additional methods ================================================================

    /**
     * @see com.blandware.atleap.service.questionnaire.QuestionnaireManager#listFilledQuestionnaires(com.blandware.atleap.common.util.QueryInfo)
     */
    public PartialCollection listFilledQuestionnaires(QueryInfo queryInfo) {
        return filledQuestionnaireDAO.listFilledQuestionnaires(queryInfo);
    }

}
